/**
 * @file rtk_cpu_cm.c
 * @author LokLiang (lokliang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-01
 *
 * @copyright Copyright (c) 2023
 *
 */

#if defined(MIX_RTK)

#include "prv_rtk_cpu.h"
#include "prv_rtk_class.h"

#include "FreeRTOSConfig.h"
#include "projdefs.h"
#include "portmacro.h"
#include "portable.h"
#include "FreeRTOS.h"

#ifndef configMAX_SYSCALL_INTERRUPT_PRIORITY
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x00 /* equivalent to 0xa0, or priority 5. */
#endif

static uint int_mask = 0;

void *pxCurrentTCB;

/**
 * @def 线程调度
 */

/**
 * @brief 初始化线程堆栈
 * @see prv_rtk_cpu.h
 *
 * @param entry 线程函数的入口
 * @param arg 附带的一个参数
 * @param stack 栈底
 * @param exit 线程函数返回的PC值
 * @return void* 初始化后的栈的值
 */
void *rtk_cpu_stack_init(void *entry, void *arg, void *stack_begin, void *stack_end, void *exit)
{
    stack_begin = (void *)((unsigned int)stack_begin & ~(portBYTE_ALIGNMENT - 1));
#if (portHAS_STACK_OVERFLOW_CHECKING == 1)
    stack_end = (void *)((unsigned int)stack_end & ~(portBYTE_ALIGNMENT - 1));
    return pxPortInitialiseStack((StackType_t *)stack_begin, (StackType_t *)stack_end, (TaskFunction_t)entry, arg);
#else
    return pxPortInitialiseStack((StackType_t *)stack_begin, (TaskFunction_t)entry, arg);
#endif
}

/**
 * @brief 结束一个线程
 *
 * @param from 指向原线程栈指针的指针
 */
void rtk_cpu_delete_thread(void *from)
{
}

/**
 * @brief 启动芯片内核的多线程模式
 * @see prv_rtk_cpu.h
 *
 * @param to 首个执行的线程的栈指针
 */
void rtk_cpu_scheduler_start(void *to)
{
    curr_thread_handle = to;
    pxCurrentTCB = &curr_thread_handle->pSP;
    portDISABLE_INTERRUPTS();
    xPortStartScheduler();
}

/**
 * @brief 执行一次上下文切换
 * @see prv_rtk_cpu.h
 *
 * @param from 指向原线程栈指针的指针
 * @param to 指向目标线程栈指针的指针
 */
void rtk_cpu_switch_to(void *from, void *to)
{
    curr_thread_handle = to;
    portYIELD();
}

/**
 * @brief 来自 port.c 的调用接口，在此接口处设置 pxCurrentTCB 的新值
 * @see port.c: void xPortPendSVHandler( void )
 *
 */
void vTaskSwitchContext(void)
{
    pxCurrentTCB = &curr_thread_handle->pSP;
}

/**
 * @brief 屏蔽中断
 * @see prv_rtk_cpu.h
 * @detail 内部函数中断屏蔽计数器mask, 初始值为0, 屏蔽一次中断递增1
 *
 * @return uint 屏蔽中断前 mask 的值
 */
size_t rtk_cpu_interrupt_save(void)
{
    if (int_mask == 0)
    {
        portDISABLE_INTERRUPTS();
    }
    return int_mask++;
}

/**
 * @brief 允许中断
 * @see prv_rtk_cpu.h
 *
 * @param mask 设置中断屏蔽计数器的值，当 mask 的值为0时允许中断
 */
void rtk_cpu_interrupt_restore(size_t mask)
{
    int_mask = mask;
    if (mask == 0)
    {
        portENABLE_INTERRUPTS();
    }
}

/**
 * @def 系统中断
 */

/**
 * @brief 初始化滴答时钟
 *
 * @param ticks_per_sec 使每秒产生多少次中断
 */
void rtk_tick_init(size_t ticks_per_sec)
{
}

/**
 * @def 系统状态
 */

/**
 * @brief 获取当前运行状态
 *
 * @return true 当前运行在中断模式
 * @return false 当前运行在线程模式
 */
bool rtk_cpu_is_isr(void)
{
#if defined(__CC_ARM)
    register uint32_t __regIPSR __asm("ipsr");
    return (__regIPSR);
#elif defined(__GNUC__)
    uint32_t result;
    __asm volatile("MRS %0, ipsr"
                   : "=r"(result));
    return !!result;
#else
#endif
}

/**
 * @brief 来自 port.c 的调用接口，在屏蔽了中断的状态下执行一次滴答时钟的中断程序
 * @see port.c: void xPortSysTickHandler( void )
 *
 * @return pdFALSE 不需要执行上下文切换
 * @return pdTRUE 需要执行上下文切换
 */
BaseType_t xTaskIncrementTick(void)
{
    _rtk_isr_tick();
    return pdFALSE;
}

/**
 * @brief 在 FreeRTOSConfig.h 定义
 * @detail
 * #define configASSERT_DEFINED                             1
 * extern void vAssertCalled( void );
 * #define configASSERT( x )    if( ( x ) == 0 ) vAssertCalled()
 *
 * @see FreeRTOSConfig.h
 */
void vAssertCalled(void)
{
    SYS_ASSERT_FALSE(1, "");
}

__weak void HardFault_Handler(void)
{
    rtk_isr_hardfault_check();
}

#endif /* #if defined(MIX_RTK) */
